package adminctl

import (
	"code.bydev.io/cht/customer/kyc-stub.git/pkg/bybit/kyc/admin/v1"
	"code.bydev.io/cht/customer/kyc-stub.git/pkg/bybit/kyc/common"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/constant"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/biz"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/config"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/helper"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycadminapi"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycadminapi/actionsvc"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycadminapi/dto"
	pvd_dto "code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycprovider/dto"
	pvd "code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycprovider/provider"
	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/monitor"
	"context"
	"git.bybit.com/svc/go/pkg/bzap"
	"git.bybit.com/svc/stub/pkg/pb/api/consts/euser"
	pb "git.bybit.com/svc/stub/pkg/pb/api/kycadmin"
	"git.bybit.com/svc/stub/pkg/pb/enums/ekycadmin"
	"git.bybit.com/svc/stub/pkg/pb/enums/kyc"
	"github.com/opentracing/opentracing-go"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
)

type AdminCtrl = *adminCtrl

type adminCtrl struct {
	logger *zap.Logger
	teller kycadminapi.Teller
	acvSvc actionsvc.ActionSvc
}

func New(h *biz.Handler) AdminCtrl {
	return &adminCtrl{
		logger: h.Logger(),
		teller: h.Teller(),
		acvSvc: actionsvc.New(h.KycAdminRepo(), h.SecHub(), h.Logger(), h.Teller()),
	}
}

func (c *adminCtrl) GetKycActionList(ctx context.Context, request *pb.GetKycActionListRequest) (resp *pb.GetKycActionListResponse, err error) {
	metrics := monitor.NewMetrics("GetKycActionList", "")

	if request.PageSize > 20 || request.PageSize < 1 {
		request.PageSize = 20
	}
	if request.PageNo < 1 || request.PageNo > 2000 {
		request.PageNo = 1
	}

	// 条件判断
	if request.MemberId == 0 && request.RecordId == "" && request.Country == "" {
		resp = new(pb.GetKycActionListResponse)
		resp.Error = biz.ErrorBadParams.CommonError("筛选条件必须至少包括：UID、通道ID、签发国家 中的一个")
		return resp, err
	}

	c.logger.Info("GetKycActionListStart", zap.Any("request", request))

	// Alpha2 转换
	request.Country = helper.CountryCode2Alpha3(request.Country)
	// Add trace
	spanPl, _ := opentracing.StartSpanFromContext(ctx, "GetActionListFromDB")
	defer spanPl.Finish()

	actList, total, err := c.acvSvc.GetActionList(
		ctx,
		&dto.ActionListCondition{
			PageNo:    request.PageNo,
			PageSize:  request.PageSize,
			MemberID:  request.MemberId,
			RecordID:  request.RecordId,
			Provider:  request.Provider,
			Decision:  request.Decision,
			Country:   request.Country,
			DocNumber: request.DocNumber,
			Level:     int(request.Level),
		},
	)
	resp = new(pb.GetKycActionListResponse)
	if err != nil {
		metrics.AddMetrics(err, "GetActionList")
		resp.Error = biz.ErrorFAIL.CommonError("Internal server error")

		return resp, err
	}
	resp.PageSize = request.PageSize
	resp.Total = total
	resp.List = make([]*pb.GetKycActionItem, 0)

	for _, raw := range actList {
		rjtRsn := ""
		if dto.Decision(raw.Decision).IsBizReject() {
			rjtRsn = raw.RejectReason
			if rjtRsn == "" {
				rjtRsn = config.CustomerReasonDefault
			}
		}
		docType := pvd.GetDocTypeDesc(pvd_dto.KYCProvider(raw.Channel), pvd_dto.DocType(raw.DocType))
		if dto.Decision(raw.Decision).IsBizSuccess() && pvd_dto.KYCProvider(raw.Channel).IsProviderSumSub() { // 兼容旧居住证错误数据
			docType = pvd_dto.DocumentTypeResidence.String()
		}
		st := ekycadmin.KYCSerialType_SERIAL_TYPE_ONBOARDING
		if raw.SerialType == 1 {
			st = ekycadmin.KYCSerialType_SERIAL_TYPE_SUPPLEMENT
		}
		item := &pb.GetKycActionItem{
			Id:                   raw.Id,
			MemberId:             raw.MemberId,
			ReviewTime:           raw.ReviewTime,
			Country:              helper.CountryNameAlpha3(raw.Country).EnName,
			Provider:             pvd_dto.KYCProvider(raw.Channel).Upper(),
			RecordId:             raw.RecordId,
			Decision:             pvd_dto.GetBizDecisionEnDesc(dto.Decision(raw.Decision), pvd_dto.AdminAction(raw.Action)),
			SiteId:               helper.GetBrokerEnName(euser.BrokerID(raw.SiteId)),
			ProviderRejectReason: raw.ProviderRejectReason,
			RejectReason:         rjtRsn,
			Level:                kyc.MemberKYCLevel(raw.Level),
			IsTransfer:           raw.IsTransfer > 0,
			DocType:              docType,
			SerialType:           st,
			BusinessId:           constant.BusinessID(raw.BusinessId).ToKYCBusinessID(),
		}
		resp.List = append(resp.List, item)
	}

	metrics.AddMetrics(nil, monitor.END)

	return resp, nil
}

func (c *adminCtrl) GetKycActionDetail(ctx context.Context, request *pb.GetKycActionDetailRequest) (resp *pb.KycActionDetailResponse, err error) {
	metrics := monitor.NewMetrics("GetKycActionDetail", "")

	resp = new(pb.KycActionDetailResponse)
	if request.GetId() < 1 {
		resp.Error = biz.ErrorBadParams.CommonError("Id must be larger than 1")
		c.logger.Info("Request params error", zap.Any("req", request))

		return resp, nil
	}

	// Add trace
	spanPl, _ := opentracing.StartSpanFromContext(ctx, "GetActionDetailFromDB")
	defer spanPl.Finish()

	record, err := c.acvSvc.GetActionDetail(ctx, &dto.ActionDetailCondition{ID: request.GetId()})
	if err != nil {
		metrics.AddMetrics(err, "GetActionDetail")
		resp.Error = biz.ErrorFAIL.CommonError("Internal Server Error")
		bzap.LogError(c.logger.With(zap.Any("req", request)), "Internal Server Error", err)

		return resp, nil
	}
	if resp == nil {
		resp.Error = biz.ErrorNoData.CommonError("No records")
		return resp, nil
	}

	metrics.AddMetrics(nil, monitor.END)

	return record, nil
}

func (c *adminCtrl) GetCountryConfig(ctx context.Context, request *v1.GetCountryConfigRequest) (resp *v1.GetCountryConfigResponse, err error) {
	metrics := monitor.NewMetrics("GetCountryConfig", "")

	if request.PageSize > 50 || request.PageSize < 1 {
		request.PageSize = 50
	}
	if request.PageNo < 1 || request.PageNo > 2000 {
		request.PageNo = 1
	}

	c.logger.Info("GetCountryConfigStart", zap.Reflect("request", request))
	resp = new(v1.GetCountryConfigResponse)
	configList, total, err := c.acvSvc.GetCountryConfigList(
		ctx,
		&dto.CountrySearchCondition{
			PageNo:      request.PageNo,
			PageSize:    request.PageSize,
			CountryCode: request.CountryCode,
			CountryName: request.CountryName,
		},
	)

	if err != nil {
		c.logger.Error("GetCountryConfigListFail", zap.Error(err), zap.Reflect("request", request))
		resp.Error = &common.Error{
			Code: int32(codes.NotFound),
		}
		return resp, err
	}

	resp.CountryConfig = configList
	resp.Total = int64(total)
	resp.PageSize = request.PageSize

	metrics.AddMetrics(nil, monitor.END)
	return resp, nil
}

func (c *adminCtrl) SetCountryConfig(ctx context.Context, request *v1.SetCountryConfigRequest) (resp *v1.SetCountryConfigResponse, err error) {
	metrics := monitor.NewMetrics("SetCountryConfig", "")
	c.logger.Info("SetCountryConfig", zap.Reflect("request", request))
	resp = new(v1.SetCountryConfigResponse)

	err = c.acvSvc.SetCountryConfig(ctx, request.CountryConfig)
	if err != nil {
		c.logger.Error("GetCountryConfigFail", zap.Error(err), zap.Reflect("request", request))
		resp.Error = &common.Error{
			Code: int32(codes.Internal),
		}
		return resp, err
	}

	metrics.AddMetrics(nil, monitor.END)
	return resp, nil
}

func (c *adminCtrl) GetCommonConfig(ctx context.Context, request *v1.GetCommonConfigRequest) (resp *v1.GetCommonConfigResponse, err error) {
	metrics := monitor.NewMetrics("GetCommonConfig", "")

	resp = new(v1.GetCommonConfigResponse)

	commonConfig, err := c.acvSvc.GetCommonConfig(ctx)
	if err != nil {
		c.logger.Error("GetCommonConfigFail", zap.Error(err), zap.Reflect("request", request))
		resp.Error = &common.Error{
			Code: int32(codes.Internal),
		}
		return resp, err
	} else {
		resp.CommonConfig = &v1.CommonConfig{
			DocSubtype: commonConfig.DocSubtype,
		}
	}

	metrics.AddMetrics(nil, monitor.END)
	return resp, nil
}

func (c *adminCtrl) SetCommonConfig(ctx context.Context, request *v1.SetCommonConfigRequest) (resp *v1.SetCommonConfigResponse, err error) {
	metrics := monitor.NewMetrics("SetCommonConfig", "")

	resp = new(v1.SetCommonConfigResponse)

	if request.CommonConfig.DocSubtype == nil {
		c.logger.Error("DocSubtype Empty", zap.Error(err), zap.Reflect("request", request))
		resp.Error = &common.Error{
			Code: int32(codes.InvalidArgument),
		}
		return resp, err
	}

	err = c.acvSvc.SetCommonConfig(ctx, request.CommonConfig)
	if err != nil {
		c.logger.Error("GetCountryConfigListFail", zap.Error(err), zap.Reflect("request", request))
		resp.Error = &common.Error{
			Code: int32(codes.Internal),
		}
		return resp, err
	}

	metrics.AddMetrics(nil, monitor.END)
	return resp, nil
}
